package com.rainy.cloud.gateway.route.service;

import com.rainy.cloud.gateway.route.entity.Route;
import com.rainy.cloud.gateway.route.entity.RouteFilter;
import com.rainy.cloud.gateway.route.entity.RoutePredicate;
import com.rainy.cloud.gateway.route.properties.RouteProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * @author user
 */
@Service
public class RouteLoadService implements ApplicationEventPublisherAware {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RouteProperties routeProperties;

    @Resource
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    private void notifyChanged() {
        publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    /**
     * 增加路由
     */
    public String add(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        notifyChanged();
        return "success";
    }

    /**
     * 增加路由
     */
    public String add(List<RouteDefinition> definitions) {
        for (RouteDefinition definition : definitions) {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            notifyChanged();
        }
        return "success";
    }

    /**
     * 更新路由
     */
    public String update(RouteDefinition definition) {
        delete(definition.getId());
        add(definition);
        return "success";
    }

    /**
     * 删除路由
     */
    public String delete(String id) {
        routeDefinitionWriter.delete(Mono.just(id));
        notifyChanged();
        return "delete success";
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        publisher = applicationEventPublisher;
    }

    /**
     * 使用实例
     * 后续进行可以使用DB进行持久化配置
     * 根据Spring Cloud Gateway的路由模型定义数据传输模型，
     * 分别创建GatewayRouteDefinition.java, GatewayPredicateDefinition.java, GatewayFilterDefinition.java这三个类
     */
    public List<RouteDefinition> loadRoute() {
        List<RouteDefinition> routeDefinitions = new ArrayList<RouteDefinition>();
        List<Route> routes = routeProperties.getRoutes();
        for (Route route : routes) {
            RouteDefinition definition = convertToRouteDefinition(route);
            routeDefinitions.add(definition);
        }
        return routeDefinitions;
    }

    /**
     * 根据定义数据获取对应路由定义对象
     * @param route
     * @return
     */
    private RouteDefinition convertToRouteDefinition(Route route) {
        //定义路由
        RouteDefinition definition = new RouteDefinition();
        definition.setId(route.getCode());
        URI uri = UriComponentsBuilder.fromUriString(route.getUrl()).build().toUri();
        definition.setUri(uri);
        //定义Predicate
        List<RoutePredicate> routePredicates = route.getRoutePredicates();
        List<PredicateDefinition> predicates = new ArrayList<PredicateDefinition>();
        for (RoutePredicate routePredicate : routePredicates) {
            PredicateDefinition predicate = new PredicateDefinition();
            predicate.setName(routePredicate.getName());
            predicate.setArgs(routePredicate.getArgs());
            predicates.add(predicate);
        }
        definition.setPredicates(predicates);
        //定义Filter
        List<RouteFilter> routeFilters = route.getRouteFilters();
        List<FilterDefinition> filters = new ArrayList<FilterDefinition>();
        for (RouteFilter routeFilter : routeFilters) {
            FilterDefinition filter = new FilterDefinition();
            filter.setName(routeFilter.getName());
            filter.setArgs(routeFilter.getArgs());
            filters.add(filter);
        }
        definition.setFilters(filters);
        return definition;
    }

//    /**
//     * 使用实例
//     * 后续进行可以使用DB进行持久化配置
//     * 根据Spring Cloud Gateway的路由模型定义数据传输模型，
//     * 分别创建GatewayRouteDefinition.java, GatewayPredicateDefinition.java, GatewayFilterDefinition.java这三个类
//     */
//    public RouteDefinition initDemo() {
//        RouteDefinition definition = new RouteDefinition();
//        definition.setId("id");
//        URI uri = UriComponentsBuilder.fromUriString("lb://rainy-cloud-consumer/").build().toUri();
//        definition.setUri(uri);
//
//        //定义断言
//        Map<String, String> predicateParams = new HashMap<>(8);
//        predicateParams.put("pattern", "/hello/**");
//        PredicateDefinition predicate = new PredicateDefinition();
//        predicate.setName("Path");
//        predicate.setArgs(predicateParams);
//        definition.setPredicates(Arrays.asList(predicate));
//
//        //定义Filter
//        FilterDefinition filter = new FilterDefinition();
//        Map<String, String> filterParams = new HashMap<>(8);
//        //该_genkey_前缀是固定的，见org.springframework.cloud.gateway.support.NameUtils类
//        filterParams.put("_genkey_0", "header");
//        filterParams.put("_genkey_1", "addHeader");
//        filter.setName("AddRequestHeader");
//        filter.setArgs(filterParams);
//
//        FilterDefinition filter1 = new FilterDefinition();
//        Map<String, String> filter1Params = new HashMap<>(8);
//        filter1Params.put("_genkey_0", "param");
//        filter1Params.put("_genkey_1", "addParam");
//        filter1.setName("AddRequestParameter");
//        filter1.setArgs(filter1Params);
//
//        /**
//         * filter名称必须是RequestRateLimiter
//         * redis-rate-limiter.replenishRate：允许用户每秒处理多少个请求
//         * redis-rate-limiter.burstCapacity：令牌桶的容量，允许在一秒钟内完成的最大请求数
//         * key-resolver：使用SpEL按名称引用bean
//         * Demo对应url：https://www.jianshu.com/p/1e4f36ec6120
//         */
//        FilterDefinition limiterFilter = new FilterDefinition();
//        Map<String, String> limiterParams = new HashMap<>(8);
//        // 每秒最大访问次数
//        limiterParams.put("redis-rate-limiter.replenishRate", "1");
//        // 令牌桶最大容量
//        limiterParams.put("redis-rate-limiter.burstCapacity", "1");
//        // 限流策略(#{@BeanName})
//        limiterParams.put("key-resolver", "#{@ipKeyResolver}");
//        // 名称是固定的，spring gateway会根据名称找对应的FilterFactory
//        limiterFilter.setName("RainyRateLimiter");
//        limiterFilter.setArgs(limiterParams);
//        definition.setFilters(Arrays.asList(filter, filter1, limiterFilter));
//        return definition;
//    }
}
